<script setup>
import { ref, h, computed, onMounted, nextTick, toRaw } from 'vue'
import { NTag, NBadge, NSpin, NButton, NTooltip } from 'naive-ui'
import { request, requestCache } from '../../utils/request'
import { size, time } from '../../utils/common'
import Console from '../Console/Index.vue'
import * as echarts from 'echarts'
import moment from 'moment'

const model = defineModel(false)
const timeColor = ms => {
    if (ms > 3000) {
        return 'warning'
    }
    return 'success'
}
const statusVNode = row => {
    switch (row.status) {
        case 'running':
            return h(NSpin, { show: false, size: 'small' })
        case 'success':
            return h(NBadge, { dot: true, type: 'success' })
        default:
            return h(
                NTooltip,
                {},
                { trigger: () => h(NBadge, { dot: true, type: 'error' }), default: row.statusText }
            )
    }
}
const menus = ref(['id', 'url', 'status', 'duration.total', 'actions'])
const columns = [
    {
        key: 'console',
        type: 'expand',
        renderExpand: row =>
            h(Console, {
                headers: row.headers,
                url: row.url,
                params: row.params,
                data: row.data,
                response: row.response
            })
    },
    {
        title: 'ID',
        key: 'id',
        align: 'center',
        ellipsis: {
            tooltip: true
        },
        width: 40
    },
    {
        title: '地址',
        key: 'url',
        align: 'center',
        ellipsis: {
            tooltip: true
        },
        minWidth: 150
    },
    {
        title: '状态',
        key: 'status',
        render: row => statusVNode(row),
        align: 'center',
        width: 100
    },
    {
        title: '异常',
        key: 'statusText',
        align: 'center',
        ellipsis: {
            tooltip: true
        },
        minWidth: 150
    },
    {
        title: '耗时',
        key: 'duration',
        align: 'center',
        children: [
            {
                title: '请求',
                key: 'duration.clientToServer',
                render: row =>
                    h(
                        NTag,
                        { type: timeColor(row.duration?.clientToServer) },
                        { default: time(row.duration?.clientToServer) }
                    ),
                align: 'center'
            },
            {
                title: '处理',
                key: 'duration.server',
                render: row =>
                    h(
                        NTag,
                        { type: timeColor(row.duration?.server) },
                        { default: time(row.duration?.server) }
                    ),
                align: 'center'
            },
            {
                title: '接收',
                key: 'duration.serverToClient',
                render: row =>
                    h(
                        NTag,
                        { type: timeColor(row.duration?.serverToClient) },
                        { default: time(row.duration?.serverToClient) }
                    ),
                align: 'center'
            }
        ]
    },
    {
        title: '耗时',
        key: 'duration.total',
        render: row =>
            h(
                NTag,
                { type: timeColor(row.duration?.total) },
                { default: time(row.duration?.total) }
            ),
        align: 'center',
        width: 100
    },
    {
        title: '响应大小',
        key: 'size',
        render: row => size(row.size),
        align: 'center',
        width: 100
    },
    {
        title: '操作',
        key: 'actions',
        render: row =>
            h(NButton, { type: 'primary', onClick: () => request(row) }, { default: '重放' }),
        align: 'center',
        fixed: true,
        width: 100,
        fixed: 'right'
    }
]
const usedColumns = computed(() => columns.filter(it => menus.value.includes(it.key)))
const open = () => {
    model.value = true
}
const chartRef = ref()
let chart = {}
const renderChart = () => {
    chart = echarts.init(chartRef.value)
    let min = Math.min(...requestCache.value.queue.map(it => it.startTime))
    const source = requestCache.value.queue.map(it => {
        return {
            startTime: it.startTime,
            startTimeGap: it.startTime - min,
            startTimeGapSecond: (it.startTime - min) / 1000,
            endTime: it.endTime,
            id: it.id,
            duration: it.duration,
            url: it.url,
            ...it.duration
        }
    })
    const option = {
        title: {
            text: '请求详情'
        },
        dataset: [
            {
                dimensions: [
                    'id',
                    'startTimeGapSecond',
                    'clientToServer',
                    'server',
                    'serverToClient',
                    'total'
                ],
                source: source
            },
            {
                transform: {
                    type: 'filter',
                    config: {},
                    print: true
                }
            }
        ],
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                type: 'shadow'
            },
            formatter: function (params) {
                console.log(params)
                const { startTime, endTime, startTimeGapSecond, id, url, duration } = params[0].data
                return [
                    url,
                    '<br/>开始时间：' + moment(startTime).format('HH:mm:ss.SSS'),
                    '<br/>结束时间：' + moment(endTime).format('HH:mm:ss.SSS'),
                    '<br/>距离初始请求差距：' + startTimeGapSecond + ' s',
                    '<br/>客户端到服务器：' + duration.clientToServer + ' ms',
                    '<br/>服务器处理：' + duration.server + ' ms',
                    '<br/>服务器到客户端：' + duration.serverToClient + ' ms',
                    '<br/>总耗时：' + duration.total + ' ms'
                ].join('')
            }
        },
        legend: {
            orient: 'horizontal',
            selected: {
                Placeholder: true,
                clientToServer: true,
                server: true,
                serverToClient: true,
                total: false
            }
        },
        grid: {
            left: 0,
            right: 0,
            bottom: 0,
            containLabel: true
        },
        xAxis: {
            type: 'value',
            splitLine: { show: false }
        },
        yAxis: {
            type: 'category'
        },
        series: [
            {
                name: 'Placeholder',
                type: 'bar',
                stack: 'duration',
                itemStyle: {
                    borderColor: 'transparent',
                    color: 'transparent'
                },
                emphasis: {
                    itemStyle: {
                        borderColor: 'transparent',
                        color: 'transparent'
                    }
                },
                endcode: {
                    x: 'id',
                    y: 'startTimeGapSecond'
                }
            },
            {
                name: 'clientToServer',
                type: 'bar',
                stack: 'duration',
                label: {
                    show: false,
                    position: 'right',
                    formatter: params => params.value.clientToServer + ' ms'
                },
                endcode: {
                    x: 'id',
                    y: 'clientToServer'
                }
            },
            {
                name: 'server',
                type: 'bar',
                stack: 'duration',
                label: {
                    show: false,
                    position: 'right',
                    formatter: params => params.value.server + ' ms'
                }
            },
            {
                name: 'serverToClient',
                type: 'bar',
                stack: 'duration',
                label: {
                    show: true,
                    position: 'right',
                    formatter: params => params.value.serverToClient + ' ms'
                }
            },
            {
                name: 'total',
                type: 'bar',
                stack: 'total',
                label: {
                    show: true,
                    position: 'right',
                    formatter: params => params.value.total + ' ms'
                },
                endcode: {
                    x: 'id',
                    y: 'total'
                }
            }
        ]
    }
    chart.on('legendselectchanged', function (params) {
        if (params.selected['Placeholder'] && params.name === 'total') {
            chart.dispatchAction({
                type: 'legendUnSelect',
                name: 'Placeholder'
            })
        } else if (params.selected['total'] && params.name === 'Placeholder') {
            chart.dispatchAction({
                type: 'legendUnSelect',
                name: 'total'
            })
        }
    })
    chart.setOption(option)
}
const onChange = value => {
    menus.value = value
    nextTick(() => {
        if (menus.value.includes('chart')) {
            renderChart()
        }
    })
}
</script>

<template>
    <slot>
        <n-flex justify="center" style="padding: 1rem 2rem">
            <div @click="open">
                请求次数 {{ requestCache.queue.length }}，耗时 {{ requestCache.duration }}
            </div>
        </n-flex>
    </slot>
    <n-modal
        v-model:show="model"
        class="w-50"
        preset="card"
        title="请求列表"
        size="huge"
        :bordered="false">
        <n-scrollbar class="min-h-50vh max-h-80vh">
            <n-flex vertical size="large">
                <n-flex vertical size="large">
                    <n-alert title="请求分析" :type="requestCache.error > 0 ? 'error' : 'success'">
                        <n-flex vertical>
                            <div>
                                发送请求
                                <n-tag type="info" strong size="small">
                                    {{ requestCache.queue.length }}
                                </n-tag>
                                个， 成功
                                <n-tag type="success" size="small">
                                    {{ requestCache.success }}
                                </n-tag>
                                个， 失败
                                <n-tag type="error" size="small">{{ requestCache.error }}</n-tag>
                                个， 请求中
                                <n-tag type="info" size="small">{{ requestCache.running }}</n-tag>
                                个， 耗时
                                <n-tag type="info" size="small">{{ requestCache.duration }}</n-tag>
                            </div>
                            <div>
                                接收数据
                                <n-tag type="info" size="small">{{ requestCache.size }}</n-tag>
                            </div>
                        </n-flex>
                    </n-alert>
                    <n-checkbox-group v-model:value="menus" :on-update:value="onChange">
                        <n-flex :size="0">
                            <n-checkbox value="id" label="ID" />
                            <n-checkbox value="url" label="地址" />
                            <n-checkbox value="status" label="状态" />
                            <n-checkbox value="duration.total" label="耗时" />
                            <n-checkbox value="actions" label="操作" />
                            <n-checkbox value="duration" label="明细" />
                            <n-checkbox value="size" label="响应" />
                            <n-checkbox value="statusText" label="异常" />
                            <n-checkbox value="console" label="详情" />
                            <n-checkbox value="chart" label="图表" />
                        </n-flex>
                    </n-checkbox-group>
                    <div class="chart" v-if="menus.includes('chart')" ref="chartRef"></div>
                </n-flex>
                <n-data-table
                    size="small"
                    bordered
                    :single-line="false"
                    :columns="usedColumns"
                    :data="requestCache.queue"
                    striped
                    :row-key="row => row.url" />
            </n-flex>
        </n-scrollbar>
    </n-modal>
</template>

<style scoped>
.chart {
    height: 300px;
    width: 100%;
}
</style>
